﻿using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace Nextensions.Security.Cryptography
{
    public class CryptTool
    {
        public const int MinPassPhraseLength = 8;
        /*private static readonly byte[] Key = { 172, 55, 164, 42, 43, 231, 178, 178, 16, 79, 198, 132, 186, 23, 190, 126, 4, 13, 178, 32, 54, 124, 80, 38, 113, 66, 235, 59, 194, 68, 84, 188 };
        private static readonly byte[] IV = { 148, 39, 109, 196, 4, 213, 45, 95, 59, 53, 58, 75, 173, 224, 3, 172 };

        public static string Encrypt(string Text)
        {
            RijndaelManaged rj = new RijndaelManaged();
            ICryptoTransform encryptor = rj.CreateEncryptor(Key, IV);

            MemoryStream memStream = new MemoryStream();

            using (CryptoStream cryptStream = new CryptoStream(memStream, encryptor, CryptoStreamMode.Write))
            {
                using (StreamWriter writer = new StreamWriter(cryptStream))
                {
                    writer.Write(Text);
                }
                rj.Clear();
            }

            return Convert.ToBase64String(memStream.ToArray());
        }

        public static string Decrypt(byte[] Buffer)
        {
            RijndaelManaged rj = new RijndaelManaged();
            ICryptoTransform decryptor = rj.CreateDecryptor(Key, IV);
            string result;

            using (MemoryStream memStream = new MemoryStream(Buffer))
            {
                using (CryptoStream csDecrypt = new CryptoStream(memStream, decryptor, CryptoStreamMode.Read))
                {
                    using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                    {
                        result = srDecrypt.ReadToEnd();
                    }
                }
            }

            return result;
        }

        public static string Decrypt(string Base64Text)
        {
            byte[] buffer = Convert.FromBase64String(Base64Text);
            return Decrypt(buffer);
        }*/

        public static byte[] Encrypt(string InputText, string PassPhrase)
        {
            RijndaelManaged RijndaelCipher = new RijndaelManaged();

            byte[] plainText = Encoding.Unicode.GetBytes(InputText);
            byte[] salt = Encoding.Unicode.GetBytes(PassPhrase);

            Rfc2898DeriveBytes secretKey = new Rfc2898DeriveBytes(PassPhrase, salt);
            ICryptoTransform Encryptor = RijndaelCipher.CreateEncryptor(secretKey.GetBytes(32), secretKey.GetBytes(16));
            MemoryStream memoryStream = new MemoryStream();
            CryptoStream cryptoStream = new CryptoStream(memoryStream, Encryptor, CryptoStreamMode.Write);
            cryptoStream.Write(plainText, 0, plainText.Length);
            cryptoStream.FlushFinalBlock();
            
            byte[] CipherBytes = memoryStream.ToArray();
            memoryStream.Close();
            cryptoStream.Close();

            return CipherBytes;
        }

        public static string Decrypt(byte[] Source, string PassPhrase)
        {
            RijndaelManaged RijndaelCipher = new RijndaelManaged();

            byte[] salt = Encoding.Unicode.GetBytes(PassPhrase);

            Rfc2898DeriveBytes SecretKey = new Rfc2898DeriveBytes(PassPhrase, salt);

            ICryptoTransform Decryptor = RijndaelCipher.CreateDecryptor(SecretKey.GetBytes(32), SecretKey.GetBytes(16));
            string DecryptedData = null;
            MemoryStream memoryStream = new MemoryStream(Source);
            //using ()
            //{
            CryptoStream cryptoStream = new CryptoStream(memoryStream, Decryptor, CryptoStreamMode.Read);
                //using ()
                //{

                    byte[] PlainText = new byte[Source.Length];

                    try
                    {
                        int DecryptedCount = cryptoStream.Read(PlainText, 0, PlainText.Length);
                        DecryptedData = Encoding.Unicode.GetString(PlainText, 0, DecryptedCount);
                    }
                    catch
                    {
                        //Probably means the pass phrase is wrong
                        return null;
                    }
                    finally
                    {
                        //memoryStream.Close();
                        //cryptoStream.Close();
                    }
                //}
            //}
            
            return DecryptedData;
        }
    }
}
